package com.dandelion.common.utils;

import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class HttpRequestDelegate {
    private HttpServletRequest request;

    private HttpRequestDelegate(HttpServletRequest request) {
        this.request = request;
    }

    public static HttpRequestDelegate delegate(HttpServletRequest request) {
        return new HttpRequestDelegate(request);
    }

    public static void assertNotEmpty(String name, String value) throws IllegalArgumentException {
        if (StringUtils.isEmpty(value)) {
            throw new IllegalArgumentException("Parameter '" + name + "' is required");
        }
    }

    public static void assertNotBlank(String name, String value) throws IllegalArgumentException {
        if (StringUtils.isBlank(value)) {
            throw new IllegalArgumentException("Parameter '" + name + "' must not be blank");
        }
    }

    private static int toInt(String value) {
        return toInt(value, 0);
    }

    private static int toInt(String value, int defaulVal) {
        if (value == null || value.isEmpty()) {
            return defaulVal;
        }
        try {
            return Integer.valueOf(value);
        } catch (Exception e) {
            return defaulVal;
        }
    }

    private static long toLong(String value) {
        return toLong(value, 0L);
    }

    private static long toLong(String value, long defaulVal) {
        if (value == null || value.isEmpty()) {
            return defaulVal;
        }
        try {
            return Long.valueOf(value);
        } catch (Exception e) {
            return defaulVal;
        }
    }

    public String getAndCheckNotBlackAndCheckLen(String name, int maxLen) {
        String value = this.getAndCheckNotBlank(name);
        if (maxLen > 0 && value.length() > maxLen) {
            throw new IllegalArgumentException("Parameter '" + name + "' length should < " + maxLen);
        }
        return value;
    }

    public String getAndCheckNotEmptyAndCheckLen(String name, int maxLen) {
        String value = this.getAndCheckNotEmpty(name);
        if (maxLen > 0 && value.length() > maxLen) {
            throw new IllegalArgumentException("Parameter '" + name + "' length should < " + maxLen);
        }
        return value;
    }

    public Long getRequiredULong(String name) throws IllegalArgumentException {
        String value = request.getParameter(name);

        assertNotEmpty(name, value);

        Long val = null;
        try {
            val = Long.valueOf(value);
        } catch (Exception e) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not an unsigned long value");
        }

        if (val <= 0L) {
            throw new IllegalArgumentException("Parameter '" + name + "' should > 0");
        }
        return val;
    }

    public Integer getRequiredUInt(String name) throws IllegalArgumentException {
        String value = request.getParameter(name);
        assertNotEmpty(name, value);

        Integer val = null;
        try {
            val = Integer.valueOf(value);
        } catch (Exception e) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not an unsigned integer value");
        }

        if (val <= 0L) {
            throw new IllegalArgumentException("Parameter '" + name + "' should > 0");
        }
        return val;
    }

    public String getAndCheckNotEmpty(String name) {
        String value = request.getParameter(name);
        assertNotEmpty(name, value);
        return value;
    }

    public String getAndCheckNotBlank(String name) {
        String value = request.getParameter(name);
        assertNotBlank(name, value);
        return value;
    }

    /**
     * if name specified value is null then return defaultValue
     *
     * @param name
     * @param defaultValue
     * @return
     */
    public String getOrDefault(String name, String defaultValue) {
        String value = request.getParameter(name);
        return value == null ? defaultValue : value;
    }

    /**
     * if name specified value is blank then return defaultValue
     *
     * @param name
     * @param defaultValue
     * @return
     */
    public String getOrDefaultIfBlank(String name, String defaultValue) {
        String value = request.getParameter(name);
        return StringUtils.isBlank(value) ? defaultValue : value;
    }

    /**
     * if name specified value is empty then return defaultValue
     *
     * @param name
     * @param defaultValue
     * @return
     */
    public String getOrDefaultIfEmpty(String name, String defaultValue) {
        String value = request.getParameter(name);
        return StringUtils.isEmpty(value) ? defaultValue : value;
    }

    public List<Long> getULongListAndCheckRequired(String name, char delimiter) throws IllegalArgumentException {
        return (List<Long>) getULongCollectionAndCheckRequired(name, delimiter, ArrayList<Long>::new);
    }

    public Collection<Long> getULongCollectionAndCheckRequired(String name, char delimiter, Supplier<Collection<Long>> supplier) throws IllegalArgumentException {
        String value = request.getParameter(name);
        assertNotBlank(name, value);

        Collection<Long> collection = supplier.get();
        String[] array = StringUtils.splitPreserveAllTokens(value, delimiter);

        Long val;
        for (String element : array) {
            val = toLong(element);
            if (val <= 0) {
                throw new IllegalArgumentException("Parameter '" + name + "' contains non unsigned long value");
            }

            collection.add(val);
        }

        return collection;
    }

    public Collection<Long> getULongCollectionAndCheckRequired(String name, Supplier<Collection<Long>> supplier) {
        return getULongCollectionAndCheckRequired(name, ',', supplier);
    }

    public List<Long> getULongListAndCheckRequired(String name) throws IllegalArgumentException {
        return getULongListAndCheckRequired(name, ',');
    }

    public Integer getInt(String name) throws IllegalArgumentException {
        String value = request.getParameter(name);
        if (StringUtils.isEmpty(value)) {
            return null;
        }

        try {
            return Integer.valueOf(value);
        } catch (Exception e) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not an integer value");
        }
    }

    public Integer getIntOrDefault(String name, int defaultValue) {
        String value = request.getParameter(name);
        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }

        try {
            return Integer.valueOf(value);
        } catch (Exception e) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not an integer value");
        }
    }

    public Double getDouble(String name) throws IllegalArgumentException {
        String value = request.getParameter(name);

        if (StringUtils.isEmpty(value)) {
            return null;
        }

        try {
            return Double.valueOf(value);
        } catch (Exception e) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not an double value");
        }
    }

    public String getString(String name) {
        return request.getParameter(name);
    }

    public Boolean getBoolean(String name) {
        String value = request.getParameter(name);
        if (StringUtils.isEmpty(value)) {
            return null;
        }

        return Boolean.valueOf(value);
    }

    public List<Integer> getIntListAndCheckRequired(String name) {
        return getIntListAndCheckRequired(name, ',');
    }

    public List<Integer> getIntListAndCheckRequired(String name, char delimiter) {
        String value = request.getParameter(name);
        assertNotBlank(name, value);

        List<Integer> intValueList = new ArrayList<>(32);
        String[] array = StringUtils.splitPreserveAllTokens(value, delimiter);

        Integer val;
        for (String element : array) {
            val = toInt(element);
            if (val <= 0) {
                throw new IllegalArgumentException("Parameter '" + name + "' contains non integer value");
            }

            intValueList.add(val);
        }

        return intValueList;
    }

    public List<String> getStringListIgnoreBlank(String name, char delimiter) throws IllegalArgumentException {
        String value = request.getParameter(name);
        if (StringUtils.isBlank(value)) {
            return null;
        }
        String[] array = StringUtils.splitPreserveAllTokens(value, delimiter);
        return Stream.of(array).filter(StringUtils::isNotBlank).collect(Collectors.toList());
    }

    public List<String> getStringListIgnoreBlank(String name) throws IllegalArgumentException {
        return getStringListIgnoreBlank(name, ',');
    }
}
